package com.wondersgroup.restbase.dao;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.List;

/**
 * 通过JPA实现的数据访问对象具体类
 * @author wondersgroup
 *
 * @param <T> 业务实体类型参数
 */
public class BaseDaoImpl<T> implements BaseDao<T> {

	private Class<T> t;
	
    protected EntityManager em;

    /**
     * 构造函数需要传入业务实体类型对象
     * @param t 业务实体类型对象
     */
	public BaseDaoImpl(final Class<T> t) {
		this.t = t;
	}

	public List<T> getAll(int... startNoAndSize) {
		// TODO Auto-generated method stub
		return findByQuery("SELECT t FROM " + t.getSimpleName() + " t", startNoAndSize);
	}

	public T findById(Serializable id) {
		// TODO Auto-generated method stub
		return em.find(t, id);
	}
	
	public T save(T object) {
		// TODO Auto-generated method stub
		T obj = em.merge(object);
		return obj;
		
	}
	
	public List<T> save(List<T> list){
		return null;
	}

	public void remove(Serializable id) {
		// TODO Auto-generated method stub
		em.remove(
				em.getReference(t, id));
	}

	public long getCount(String sql, Object... values) {
		// TODO Auto-generated method stub
		return (Long) findUniqueByQuery(sql, values);
	}

	public boolean exists(Serializable id) {
		// TODO Auto-generated method stub
		return em.contains(id);
	}

	public List<T> findByProperty(String propertyName, Object value,
			int... startNoAndSize) {
		// TODO Auto-generated method stub
		final String sql = " from " + t.getSimpleName() + " obj where obj."
				+ propertyName + "= ?";
		return findByQuery(sql, new Object[] { value }, startNoAndSize);
	}

	public List<T> findLikeProperty(String propertyName, Object value,
			int... startNoAndSize) {
		// TODO Auto-generated method stub
		final String sql = " from " + t.getSimpleName() + " obj where obj."
				+ propertyName + "like '%?%'";
		return findByQuery(sql, new Object[] { value }, startNoAndSize);
	}

	public T findUniqueByProperty(String propertyName, Object value) {
		// TODO Auto-generated method stub
		final String sql = " from " + t.getSimpleName() + " obj where obj."
				+ propertyName + "= ?";
		return findUniqueByQuery(sql, value);
	}

	public List<T> findAllByQuery(String sql, Object... values) {
		// TODO Auto-generated method stub
		return findByQuery(sql, values);
	}

	/**
	 * 根据查询语句和分页条件加载业务对象
	 * @param sql 查询语句
	 * @param startNoAndSize 分页条件
	 * @return 业务对象集合
	 */
	private List<T> findByQuery(String sql, int... startNoAndSize) {
		return findByQuery(sql, null, startNoAndSize);
	}

	@SuppressWarnings("unchecked")
	public List<T> findByQuery(String sql, Object[] values,
			int... startNoAndSize) {
		// TODO Auto-generated method stub
		Query query = getQuery(sql);
		setPageInfo(query, startNoAndSize);
		setParameter(values, query);
		return query.getResultList();
	}

	/**
	 * 构造JPA的查询对象
	 * @param sql jpa查询语句
	 * @return jpa查询对象
	 */
	private Query getQuery(String sql) {
		return em.createQuery(sql);
	}

	/**
	 * 设置JPA查询对象的预编译参数的方法
	 * @param values 预编译参数数组
	 * @param query 查询对象
	 */
	private void setParameter(Object[] values, Query query) {
		if (values == null) {
			return;
		}
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i + 1, values[i]);
		}
	}

	/**
	 * 设置jpa查询对象分页条件的方法
	 * @param query 查询对象
	 * @param startNoAndSize 分页条件
	 */
	private void setPageInfo(Query query, int... startNoAndSize) {
		if (startNoAndSize != null && startNoAndSize.length > 1) {
			if (startNoAndSize[0] >= 0)
				query.setFirstResult(startNoAndSize[0]);
			if (startNoAndSize[1] > 0)
				query.setMaxResults(startNoAndSize[1]);
		}
	}

	@SuppressWarnings("unchecked")
	public T findUniqueByQuery(String sql, Object... values) {
		// TODO Auto-generated method stub
		Query query = getQuery(sql);
		if(values != null)
			setParameter(values, query);
		//Object result = null;
		try {
			//return (T)query.getSingleResult();
			List<T> list = query.getResultList();
		    if (list.isEmpty()) {
		        return null;
		    }
		    return list.get(0);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			return null;
		}
		//return (T) result;
	}

	@Override
	public int executeUpdate(String sql, Object... values) {
		Query query = getQuery(sql);
		if(values != null && values.length > 0)
			setParameter(values, query);
		return query.executeUpdate();
	}
}
